<?php
declare (strict_types=1);

namespace app\api\controller;

use app\BaseController;
use app\lib\exception\BaseException;
use app\middleware\api\Auth;
use app\model\CouponUsers;
use app\model\Product;
use app\validate\api\CheckId;
use dh2y\qrcode\QRcode;
use think\facade\Db;
use app\model\Order as OrderModel;

class Order extends BaseController
{
    protected $middleware = [Auth::class];

    /**
     * 下单
     * @return \think\response\Json
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function index()
    {
        //需要判断是否是多规格商品sku
        (new \app\validate\api\Order())->goCheck();
        $params = request()->param();
        $userid = request()->userid;
        $product = Product::whereIn('id', array_column($params['products'], 'id'))->select();
        $product->isEmpty() ? throw new BaseException(['msg' => '該商品已下架！']) : true;
        $total = 0;
        $goods = array_column($params['products'], null, 'id');
        $insertData = array();
        $carts = $params['carts_id'] ?? 0;

        // 计算总价检测库存
        foreach ($product as $item) {
            if ($item->num < $goods[$item->id]['num']) {
                throw new BaseException(['msg' => $item->name . '庫存不足']);
            }
            $insertData[] = [
                'product_id' => (int)$item->id,
                'num' => (int)$goods[$item->id]['num'],
                'sku_id' => (int)isset($goods[$item->id]['sku_id']) ? $goods[$item->id]['sku_id'] : 0,
                'price' => $item->price
            ];
            $total += $item->price * $goods[$item->id]['num'];
        }

        //检查优惠券是否已失效
        if (!empty($params['coupon_id'])) {
            $total=$this->isCheckCoupon($total,$userid,$params['coupon_id']);
        }
        return $this->success(['order_id'=>$this->createOrder($params,$userid,$insertData,$carts,$total)]);
    }


    /**
     * 订单详情
     * @return \think\response\Json
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function details()
    {
        (new CheckId())->goCheck();
        $id = request()->param('id');
        $data = OrderModel::where('id', $id)->with('detail.product')->select();
        return $this->success($data);
    }


    /**
     * 订单列表
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderList($limit = 10)
    {
        $order_type = \request()->param('order_type', 0);
        $data = OrderModel::when($order_type == OrderModel::BOOKING, function ($query) {
            $query->where('order_type', OrderModel::BOOKING);
        })->when($order_type == OrderModel::PROMPTLY, function ($query) {
            $query->where('order_type', OrderModel::PROMPTLY);
        })
            ->where('users_id', request()->userid)
            ->with('detail.product')
            ->order('created_at','desc')
            ->paginate($limit);
        return $this->success($data);
    }


    /**
     * 生产订单
     * @param $params
     * @param $userid
     * @param $insertData
     * @param $carts
     * @param $total
     * @return \think\response\Json
     * @throws BaseException
     */
    private function createOrder($params,$userid,$insertData,$carts,$total)
    {
        Db::startTrans();   //开启事务
        try {
            //生成订单
            $order = OrderModel::create([
                'order_no' => createOrderNo(),
                'pay_price' => $total,
                'pay_mode' => $params['pay_mode'],
                'delivery_type' => $params['delivery_type'],
                'order_type' => $params['order_type'],
                'time' => $params['time'],
                'remark' => $params['pay_mode'] ?? '',
                'address' => $params['address'],
                'users_id' => $userid,
                'coupon_id' => $params['coupon_id'] ?? 0
            ]);

            //生成订单详情
            $order->detail()->saveAll($insertData);
            //删除结算的购物车
            \app\model\Carts::where('id', 'in', $carts)
                ->where('users_id', $userid)
                ->delete();
            //直接减去库存量，避免高并发超卖。后期有时间用mq,或队列。
            array_walk($insertData, function ($v) {
                Product::where('id', $v['product_id'])->dec('num', $v['num'])->update();
            });
            Db::commit();
            $code=new QRcode();
            $filePath =$code->png('訂單編號：'.$order->order_no,false, 6)->getPath(false);
            OrderModel::where('id',$order->id)->update(['qrcode'=>ossUpload($filePath)]);
            return  $order->id;
//            return $this->success(['order_id' => $order->id]);
        } catch (\Exception $e) {
            Db::rollback();
            throw new BaseException(['msg' => $e]);
        }
    }

    /**
     * 判断是否使用优惠
     * @param $total
     * @param $userid
     * @param $coupon_id
     * @return float|int
     * @throws BaseException
     */
    private function isCheckCoupon($total,$userid,$coupon_id)
    {

            $coupon = CouponUsers::isCheckCoupon($coupon_id, $userid);
            if(!$coupon) throw new BaseException(['msg' => '沒有該優惠券']);
            //判读优惠券是否过期
            if ($coupon->coupon->end_time < time()) throw new BaseException(['msg' => '該優惠券已過期']);
            $total = $this->atOnce($coupon->coupon->condition, $total, $coupon->coupon->type, $coupon->coupon->money);
            return $total;
    }

    /**
     * 计算折扣
     * @param $original_price
     * @param $discount_rate
     * @return float|int
     */
    private function getDiscountedPrice($original_price, $discount_rate)
    {
        $discounted_price = $original_price * $discount_rate / 10;
        return $discounted_price;
    }


    /**
     * 计算满减优惠
     *
     * @param float $condition 满减条件
     * @param float $total 订单总金额
     * @param float $money 优惠金额
     *
     * @return float 优惠后的订单总金额
     * @throws BaseException
     */
    private function applyFullMin($condition, $total, $money)
    {
        if ($total >= $condition) {
            $total -= $money;
        } else {
            throw new BaseException(['msg' => '该优惠券需要凑够' . $condition . '才能使用']);
        }
        return $total;
    }

    /**
     * 计算满折优惠
     *
     * @param float $condition 满折条件
     * @param float $total 订单总金额
     * @param float $discount 折扣率
     *
     * @return float 优惠后的订单总金额
     * @throws BaseException
     */
    private function applyFullDiscount($condition, $total, $discount)
    {
        if ($total >= $condition) {
            $total = $this->getDiscountedPrice($total, $discount);
        } else {
            throw new BaseException(['msg' => '该优惠券需要凑够' . $condition . '才能使用']);
        }
        return $total;
    }

    /**
     * 计算立减优惠
     *
     * @param float $total 订单总金额
     * @param float $money 优惠金额
     *
     * @return float 优惠后的订单总金额
     */
    private function applyImmediateMin($total, $money)
    {
        return $total - $money;
    }

    /**
     * 计算立折优惠
     *
     * @param float $total 订单总金额
     * @param float $discount 折扣率
     * @return float 优惠后的订单总金额
     */
    private function applyImmediateDiscount($total, $discount)
    {
        return $this->getDiscountedPrice($total, $discount);
    }

    /**
     * 计算优惠金额
     *
     * @param float $condition 优惠条件
     * @param float $total 订单总金额
     * @param int $type 优惠类型
     * @param float $money 优惠金额/折扣率
     *
     * @return float 优惠后的订单总金额
     * @throws BaseException
     */
    private function atOnce($condition, $total, $type, $money)
    {
        switch ($type) {
            case CouponUsers::FULL_MIN:
                $total = $this->applyFullMin($condition, $total, $money);
                break;
            case CouponUsers::FULL_Z:
                $total = $this->applyFullDiscount($condition, $total, $money);
                break;
            case CouponUsers::NOW_MIN:
                $total = $this->applyImmediateMin($total, $money);
                break;
            case CouponUsers::NOW_Z:
                $total = $this->applyImmediateDiscount($total, $money);
                break;
        }
        return $total;
    }


}
